package com.yb.framework.log.aspectj;

import java.lang.reflect.Method;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.yb.common.constant.Constants;
import com.yb.common.utils.ExceptionUtil;
import com.yb.common.utils.IpUtil;
import com.yb.common.utils.ServletUtil;
import com.yb.common.utils.SnowflakeIdWorker;
import com.yb.framework.log.annotation.Log;
import com.yb.framework.security.utils.SecurityUtil;
import com.yb.project.system.domain.SysLogOperate;
import com.yb.project.system.service.SysLogOperateService;

/**
 * 操作日志记录处理
 */
@Aspect
@Component
public class LogAspectj {
	
	@Autowired
	private SysLogOperateService sysLogOperateService;

	private static final Logger logger = LoggerFactory.getLogger(LogAspectj.class);

	/** 排除敏感属性字段 */
	// public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };

	/**
	 * 配置织入点
	 */
	@Pointcut("@annotation(com.yb.framework.log.annotation.Log)")
	public void logPointCut() {
	}

	/**
	 * 请求成功处理
	 */
	@AfterReturning(pointcut = "logPointCut()", returning = "ajaxResult")
	public void doAfterReturning(JoinPoint joinPoint, Object ajaxResult) {
		handleLog(joinPoint, ajaxResult, null);
	}

	/**
	 * 拦截异常处理
	 */
	@AfterThrowing(value = "logPointCut()", throwing = "exception")
	public void doAfterThrowing(JoinPoint joinPoint, Exception exception) {
		handleLog(joinPoint, null, exception);
	}

	protected void handleLog(JoinPoint joinPoint, Object ajaxResult, final Exception exception) {
		try {
			// 获得注解
			Log annoLog = getAnnotationLog(joinPoint);
			if (annoLog == null) {
				return;
			}
			
			SysLogOperate sysLogOperate = new SysLogOperate();
			sysLogOperate.setId(SnowflakeIdWorker.getInstance().getId());
			sysLogOperate.setLabel(annoLog.label());
			sysLogOperate.setOperateType(annoLog.operateType().toString());
			sysLogOperate.setOperateUserType(annoLog.operateUserType().toString());
			
			sysLogOperate.setRequestUrl(ServletUtil.getRequest().getRequestURI());
			sysLogOperate.setRequestMethod(ServletUtil.getRequest().getMethod());
			sysLogOperate.setRequestParams(getRequestParams(joinPoint.getArgs()));
			sysLogOperate.setIpAddr(IpUtil.getIpAddr(ServletUtil.getRequest()));
			sysLogOperate.setOperateUser(SecurityUtil.getUsername());
			sysLogOperate.setOperateTime(new Date());
			
			if (exception == null) {
				// 操作成功
				sysLogOperate.setStatus(Constants.SUCCESS);
				sysLogOperate.setAjaxResult(ajaxResult == null ? null : ajaxResult.toString());
				sysLogOperate.setMessage(ajaxResult == null ? annoLog.label() + "成功" : JSON.parseObject(ajaxResult.toString()).getString("message"));
			} else {
				// 操作失败，抛出异常
				sysLogOperate.setStatus(Constants.ERROR);
				sysLogOperate.setAjaxResult(exception.getMessage());
				sysLogOperate.setExceptionMsg(ExceptionUtil.getStackTrace(exception));
				sysLogOperate.setMessage(annoLog.label() + "失败");
			}

			// 异步记录操作日志
			sysLogOperateService.insertLogAsync(sysLogOperate);
		} catch (Exception e) {
			logger.error("记录异常日志失败", e);	
		}
	}

	/**
	 * 获取日志注解
	 */
	private Log getAnnotationLog(JoinPoint joinPoint) throws Exception {
		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
		Method method = methodSignature.getMethod();
		if (method != null) {
			return method.getAnnotation(Log.class);
		}
		return null;
	}
	
	/**
	 * 获取请求参数
	 */
	public static String getRequestParams(Object[] args) {
		String params = "";
		if(args != null && args.length > 0) {
			for (Object arg : args) {
				 if (!(arg instanceof MultipartFile || arg instanceof HttpServletRequest || 
						 arg instanceof HttpServletResponse)) {
					 params = params + JSON.toJSONString(arg) + " ";
				 }
			}
		}
		return params.trim();
	}
}
